"""
RagFlow API 模块
用于与 RagFlow 服务端进行交互
"""

import os
import json
from typing import Dict, List, Optional, Tuple, Union, Any

import requests

from ragflow_client.config import RagFlowConfig
from ragflow_client.utils.logger import get_logger

logger = get_logger(__name__)


class RagFlowAPI:
    """RagFlow API 客户端"""
    
    def __init__(self, config: Optional[RagFlowConfig] = None):
        """
        初始化 RagFlow API 客户端
        
        Args:
            config: RagFlow 配置对象，如果为 None 则从环境变量加载
        """
        self.config = config or RagFlowConfig.from_env()
    
    def get_headers(self, content_type: str = "application/json") -> Dict[str, str]:
        """
        获取 API 请求头
        
        Args:
            content_type: 内容类型，默认为 application/json
            
        Returns:
            包含认证信息的请求头字典
        """
        headers = {
            "Authorization": f"Bearer {self.config.api_key}"
        }
        
        if content_type:
            headers["Content-Type"] = content_type
            
        return headers
    
    def is_success(self, response: Dict[str, Any]) -> bool:
        """
        检查 API 响应是否成功
        
        Args:
            response: API 响应数据
            
        Returns:
            如果响应成功则返回 True，否则返回 False
        """
        return response.get("code") == 0
    
    def check_connection(self) -> Tuple[bool, str]:
        """
        检查与 RagFlow API 的连接
        
        Returns:
            (成功状态, 消息) 元组
        """
        logger.info(f"检查 API 连接: {self.config.api_url}")
        
        url = f"{self.config.api_url}/datasets/{self.config.kb_id}/documents?page=1&page_size=1"
        
        try:
            logger.debug(f"请求 URL: {url}")
            logger.debug(f"请求头: {self.get_headers()}")
            
            response = requests.get(url, headers=self.get_headers())
            
        except Exception as e:
            error_msg = f"请求失败，请检查 API 配置: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
        
        if response.status_code != 200:
            error_msg = f"请求失败，状态码: {response.status_code}"
            logger.error(error_msg)
            return False, error_msg
        
        data = response.json()
        
        if self.is_success(data):
            logger.info(f"RagFlow 版本: {data.get('data')}")
            return True, "API 连接成功"
        
        code = data.get("code")
        message = data.get("message", "")
        
        if code in (401, 403):
            error_msg = "认证失败/未授权，请检查 API 密钥配置"
            logger.error(error_msg)
            return False, error_msg
        elif code == 100 or '404' in message:
            error_msg = "API 地址配置错误，请检查 API URL 配置"
            logger.error(error_msg)
            return False, error_msg
        else:
            error_msg = f"请求失败: {message}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 知识库管理 API ====================
    
    def list_datasets(self, page: int = 1, page_size: int = 10) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取知识库列表
        
        Args:
            page: 页码，从 1 开始
            page_size: 每页数量
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/datasets?page={page}&page_size={page_size}"
        
        try:
            logger.debug(f"请求知识库列表: {url}")
            logger.debug(f"请求头: {self.get_headers()}")
            
            # 添加超时设置，避免长时间等待
            response = requests.get(url, headers=self.get_headers(), timeout=10)
            
            # 记录响应状态码和内容
            logger.debug(f"响应状态码: {response.status_code}")
            
            if response.status_code != 200:
                try:
                    # 尝试解析错误响应
                    error_content = response.json()
                    error_msg = f"获取知识库列表失败，状态码: {response.status_code}, 错误: {error_content}"
                except:
                    # 如果无法解析JSON，直接使用文本内容
                    error_msg = f"获取知识库列表失败，状态码: {response.status_code}, 响应: {response.text[:200]}"
                
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            logger.debug(f"响应数据: {data}")
            
            if self.is_success(data):
                return True, data
            else:
                # 确保 data 是字典类型，避免对列表使用 get 方法
                if isinstance(data, dict):
                    error_msg = f"获取知识库列表失败: {data.get('message', '')}"
                else:
                    error_msg = f"获取知识库列表失败: 响应格式不正确 - {data}"
                logger.error(error_msg)
                return False, error_msg
                
        except requests.exceptions.Timeout:
            error_msg = f"获取知识库列表超时，请检查API地址 {self.config.api_url} 是否可访问"
            logger.error(error_msg)
            return False, error_msg
        except requests.exceptions.ConnectionError:
            error_msg = f"连接API服务器失败，请检查API地址 {self.config.api_url} 是否正确"
            logger.error(error_msg)
            return False, error_msg
        except Exception as e:
            error_msg = f"获取知识库列表失败: {str(e)}"
            logger.error(error_msg)
            import traceback
            logger.error(f"详细错误: {traceback.format_exc()}")
            return False, error_msg
    
    def get_dataset(self, dataset_id: str) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取知识库详情
        
        Args:
            dataset_id: 知识库 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/datasets/{dataset_id}"
        
        try:
            logger.debug(f"请求知识库详情: {url}")
            response = requests.get(url, headers=self.get_headers())
            
            if response.status_code != 200:
                error_msg = f"获取知识库详情失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"获取知识库详情失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"获取知识库详情失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def create_dataset(self, name: str, description: str = "", embedding_model: str = "text2vec-base") -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        创建知识库
        
        Args:
            name: 知识库名称
            description: 知识库描述
            embedding_model: 嵌入模型名称
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/datasets"
        
        payload = {
            "name": name,
            "description": description,
            "embedding_model": embedding_model
        }
        
        try:
            logger.debug(f"创建知识库: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.post(
                url=url,
                headers=self.get_headers(),
                json=payload
            )
            
            if response.status_code != 200:
                error_msg = f"创建知识库失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"创建知识库失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"创建知识库失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def update_dataset(self, dataset_id: str, name: str = None, description: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        更新知识库
        
        Args:
            dataset_id: 知识库 ID
            name: 知识库名称
            description: 知识库描述
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/datasets/{dataset_id}"
        
        payload = {}
        if name is not None:
            payload["name"] = name
        if description is not None:
            payload["description"] = description
        
        try:
            logger.debug(f"更新知识库: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.put(
                url=url,
                headers=self.get_headers(),
                json=payload
            )
            
            if response.status_code != 200:
                error_msg = f"更新知识库失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"更新知识库失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"更新知识库失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def delete_dataset(self, dataset_id: str) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        删除知识库
        
        Args:
            dataset_id: 知识库 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/datasets/{dataset_id}"
        
        try:
            logger.debug(f"删除知识库: {url}")
            
            response = requests.delete(
                url=url,
                headers=self.get_headers()
            )
            
            if response.status_code != 200:
                error_msg = f"删除知识库失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"删除知识库失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"删除知识库失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 文档解析 API ====================
    
    def parse_document(self, dataset_id: str = None, document_id: str = None, document_ids: List[str] = None, parser_id: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        解析文档，将文档转换为知识块
        
        Args:
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            document_id: 单个文档 ID（已废弃，请使用document_ids）
            document_ids: 文档 ID 列表，必须指定
            parser_id: 解析器 ID，如果为 None 则使用配置中的解析器 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        parser_id = parser_id or self.config.parser_id
        
        # 处理document_id和document_ids的兼容性
        if document_ids is None:
            if document_id:
                document_ids = [document_id]
            else:
                error_msg = "文档 ID 不能为空"
                logger.error(error_msg)
                return False, error_msg
        
        url = f"{self.config.api_url}/datasets/{dataset_id}/chunks"
        
        payload = {
            "document_ids": document_ids,
            "parser_id": parser_id
        }
        
        try:
            logger.debug(f"解析文档: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.post(
                url=url,
                headers=self.get_headers(),
                json=payload
            )
            
            if response.status_code != 200:
                error_msg = f"解析文档失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"解析文档失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"解析文档失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def list_chunks(self, dataset_id: str = None, document_id: str = None, page: int = 1, page_size: int = 10) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取知识块列表
        
        Args:
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            document_id: 文档 ID，如果指定则只返回该文档的知识块
            page: 页码，从 1 开始
            page_size: 每页数量
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/chunks?page={page}&page_size={page_size}"
        
        if document_id:
            url += f"&document_id={document_id}"
        
        try:
            logger.debug(f"请求知识块列表: {url}")
            response = requests.get(url, headers=self.get_headers())
            
            if response.status_code != 200:
                error_msg = f"获取知识块列表失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"获取知识块列表失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"获取知识块列表失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def get_chunk(self, chunk_id: str, dataset_id: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取知识块详情
        
        Args:
            chunk_id: 知识块 ID
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/chunks/{chunk_id}"
        
        try:
            logger.debug(f"请求知识块详情: {url}")
            response = requests.get(url, headers=self.get_headers())
            
            if response.status_code != 200:
                error_msg = f"获取知识块详情失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"获取知识块详情失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"获取知识块详情失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def delete_chunk(self, chunk_id: str, dataset_id: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        删除知识块
        
        Args:
            chunk_id: 知识块 ID
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/chunks/{chunk_id}"
        
        try:
            logger.debug(f"删除知识块: {url}")
            
            response = requests.delete(
                url=url,
                headers=self.get_headers()
            )
            
            if response.status_code != 200:
                error_msg = f"删除知识块失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"删除知识块失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"删除知识块失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def create_chunk(self, dataset_id: str = None, content: str = "", metadata: Dict[str, Any] = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        创建知识块
        
        Args:
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            content: 知识块内容
            metadata: 知识块元数据
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/chunks"
        
        payload = {
            "content": content
        }
        
        if metadata:
            payload["metadata"] = metadata
        
        try:
            logger.debug(f"创建知识块: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.post(
                url=url,
                headers=self.get_headers(),
                json=payload
            )
            
            if response.status_code != 200:
                error_msg = f"创建知识块失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"创建知识块失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"创建知识块失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def update_chunk(self, chunk_id: str, dataset_id: str = None, content: str = None, metadata: Dict[str, Any] = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        更新知识块
        
        Args:
            chunk_id: 知识块 ID
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            content: 知识块内容
            metadata: 知识块元数据
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/chunks/{chunk_id}"
        
        payload = {}
        if content is not None:
            payload["content"] = content
        if metadata is not None:
            payload["metadata"] = metadata
        
        try:
            logger.debug(f"更新知识块: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.put(
                url=url,
                headers=self.get_headers(),
                json=payload
            )
            
            if response.status_code != 200:
                error_msg = f"更新知识块失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"更新知识块失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"更新知识块失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 文档管理 API ====================
    
    def list_documents(self, dataset_id: str = None, page: int = 1, page_size: int = 10) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取文档列表
        
        Args:
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            page: 页码，从 1 开始
            page_size: 每页数量
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/documents?page={page}&page_size={page_size}"
        
        try:
            logger.debug(f"请求文档列表: {url}")
            logger.debug(f"请求头: {self.get_headers()}")
            
            # 添加超时设置，避免长时间等待
            response = requests.get(url, headers=self.get_headers(), timeout=10)
            
            # 记录响应状态码和内容
            logger.debug(f"响应状态码: {response.status_code}")
            logger.debug(f"响应内容: {response.content}")
            
            if response.status_code != 200:
                try:
                    # 尝试解析错误响应
                    error_content = response.json()
                    error_msg = f"获取文档列表失败，状态码: {response.status_code}, 错误: {error_content}"
                except:
                    # 如果无法解析JSON，直接使用文本内容
                    error_msg = f"获取文档列表失败，状态码: {response.status_code}, 响应: {response.text[:200]}"
                
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            logger.debug(f"响应数据: {data}")
            
            if self.is_success(data):
                # 记录数据结构信息
                if isinstance(data, dict):
                    if "data" in data:
                        data_field = data["data"]
                        if isinstance(data_field, dict) and "docs" in data_field:
                            items = data_field["docs"]
                            logger.debug(f"文档列表包含 {len(items)} 个项目")
                        elif isinstance(data_field, list):
                            logger.debug(f"data字段是列表，包含 {len(data_field)} 个项目")
                        else:
                            logger.warning(f"data字段既不是包含items的字典也不是列表: {type(data_field)}")
                    else:
                        logger.warning(f"响应中没有data字段: {list(data.keys())}")
                else:
                    logger.warning(f"响应不是字典类型: {type(data)}")
                
                return True, data
            else:
                # 确保 data 是字典类型，避免对列表使用 get 方法
                if isinstance(data, dict):
                    error_msg = f"获取文档列表失败: {data.get('message', '')}"
                else:
                    error_msg = f"获取文档列表失败: 响应格式不正确 - {data}"
                logger.error(error_msg)
                return False, error_msg
                
        except requests.exceptions.Timeout:
            error_msg = f"获取文档列表超时，请检查API地址 {self.config.api_url} 是否可访问"
            logger.error(error_msg)
            return False, error_msg
        except requests.exceptions.ConnectionError:
            error_msg = f"连接API服务器失败，请检查API地址 {self.config.api_url} 是否正确"
            logger.error(error_msg)
            return False, error_msg
        except Exception as e:
            error_msg = f"获取文档列表失败: {str(e)}"
            logger.error(error_msg)
            import traceback
            logger.error(f"详细错误: {traceback.format_exc()}")
            return False, error_msg
    
    def get_document(self, document_id: str, dataset_id: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取文档详情
        
        Args:
            document_id: 文档 ID
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/documents/{document_id}"
        
        try:
            logger.debug(f"请求文档详情: {url}")
            response = requests.get(url, headers=self.get_headers())
            
            if response.status_code != 200:
                error_msg = f"获取文档详情失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"获取文档详情失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"获取文档详情失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def upload_files(self, files: List[str], dataset_id: str = None, parser_id: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        上传文件到知识库
        
        Args:
            files: 文件路径列表
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            parser_id: 解析器 ID，如果为 None 则使用配置中的解析器 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        parser_id = parser_id or self.config.parser_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/documents"
        
        try:
            # 导入文件名截断函数
            from ragflow_client.utils.file_util import truncate_filename
            
            # 准备上传文件
            upload_files = []
            for file_path in files:
                try:
                    file_obj = open(file_path, "rb")
                    
                    # 获取文件名并截断，确保不超过128字节
                    original_filename = os.path.basename(file_path)
                    truncated_filename = truncate_filename(original_filename, 128)
                    
                    # 如果文件名被截断，记录日志
                    if original_filename != truncated_filename:
                        logger.info(f"文件名已截断: {original_filename} -> {truncated_filename}")
                    
                    # 使用截断后的文件名
                    upload_files.append(("file", (truncated_filename, file_obj)))
                    
                except Exception as e:
                    logger.error(f"打开文件失败: {file_path}, 错误: {str(e)}")
                    # 关闭已打开的文件
                    for _, f_tuple in upload_files:
                        if isinstance(f_tuple, tuple) and len(f_tuple) > 1:
                            f_tuple[1].close()
                        else:
                            f_tuple.close()
                    return False, f"打开文件失败: {file_path}, 错误: {str(e)}"
            
            # 添加解析器参数
            data = {"parser_id": parser_id}
            
            # 发送请求
            logger.debug(f"上传文件到: {url}")
            logger.debug(f"解析器 ID: {parser_id}")
            response = requests.post(
                url=url,
                headers=self.get_headers(content_type=""),  # 上传文件不需要设置 Content-Type
                files=upload_files,
                data=data
            )
            
            # 关闭文件
            for _, f_tuple in upload_files:
                if isinstance(f_tuple, tuple) and len(f_tuple) > 1:
                    f_tuple[1].close()
                else:
                    f_tuple.close()
            
            logger.debug(f"上传响应状态码: {response.status_code}")
            logger.debug(f"上传响应内容: {response.text}")
            
            if response.status_code != 200:
                error_msg = f"上传失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"上传失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
            
        except Exception as e:
            error_msg = f"上传文件失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    def delete_document(self, document_id: str, dataset_id: str = None) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        删除文档
        
        Args:
            document_id: 文档 ID
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/documents/{document_id}"
        
        try:
            logger.debug(f"删除文档: {url}")
            
            response = requests.delete(
                url=url,
                headers=self.get_headers()
            )
            
            if response.status_code != 200:
                error_msg = f"删除文档失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"删除文档失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"删除文档失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 检索 API ====================
    
    def search(self, query: str, dataset_id: str = None, top_k: int = 5, filter_threshold: float = 0.0) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        搜索知识库
        
        Args:
            query: 查询文本
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            top_k: 返回结果数量
            filter_threshold: 过滤阈值，相似度低于该值的结果将被过滤
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/search"
        
        payload = {
            "query": query,
            "top_k": top_k,
            "filter_threshold": filter_threshold
        }
        
        try:
            logger.debug(f"搜索知识库: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.post(
                url=url,
                headers=self.get_headers(),
                json=payload
            )
            
            if response.status_code != 200:
                error_msg = f"搜索失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"搜索失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"搜索失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 聊天 API ====================
    
    def chat(self, query: str, dataset_id: str = None, history: List[Dict[str, str]] = None, 
             stream: bool = False, top_k: int = 5, filter_threshold: float = 0.0) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        与知识库进行对话
        
        Args:
            query: 用户问题
            dataset_id: 知识库 ID，如果为 None 则使用配置中的知识库 ID
            history: 对话历史，格式为 [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]
            stream: 是否使用流式响应
            top_k: 检索结果数量
            filter_threshold: 过滤阈值，相似度低于该值的结果将被过滤
            
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        dataset_id = dataset_id or self.config.kb_id
        url = f"{self.config.api_url}/datasets/{dataset_id}/chat"
        
        payload = {
            "query": query,
            "stream": stream,
            "search_params": {
                "top_k": top_k,
                "filter_threshold": filter_threshold
            }
        }
        
        if history:
            payload["history"] = history
        
        try:
            logger.debug(f"知识库对话: {url}")
            logger.debug(f"请求参数: {payload}")
            
            response = requests.post(
                url=url,
                headers=self.get_headers(),
                json=payload,
                stream=stream
            )
            
            if response.status_code != 200:
                error_msg = f"对话失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            if stream:
                # 流式响应处理
                return True, response
            else:
                # 普通响应处理
                data = response.json()
                if self.is_success(data):
                    return True, data
                else:
                    error_msg = f"对话失败: {data.get('message', '')}"
                    logger.error(error_msg)
                    return False, error_msg
                
        except Exception as e:
            error_msg = f"对话失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 解析器 API ====================
    
    def list_parsers(self) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取解析器列表
        
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/parsers"
        
        try:
            logger.debug(f"请求解析器列表: {url}")
            response = requests.get(url, headers=self.get_headers())
            
            if response.status_code != 200:
                error_msg = f"获取解析器列表失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"获取解析器列表失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"获取解析器列表失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    # ==================== 嵌入模型 API ====================
    
    def list_embedding_models(self) -> Tuple[bool, Union[Dict[str, Any], str]]:
        """
        获取嵌入模型列表
        
        Returns:
            (成功状态, 响应数据或错误消息) 元组
        """
        url = f"{self.config.api_url}/embedding_models"
        
        try:
            logger.debug(f"请求嵌入模型列表: {url}")
            response = requests.get(url, headers=self.get_headers())
            
            if response.status_code != 200:
                error_msg = f"获取嵌入模型列表失败，状态码: {response.status_code}"
                logger.error(error_msg)
                return False, error_msg
            
            data = response.json()
            if self.is_success(data):
                return True, data
            else:
                error_msg = f"获取嵌入模型列表失败: {data.get('message', '')}"
                logger.error(error_msg)
                return False, error_msg
                
        except Exception as e:
            error_msg = f"获取嵌入模型列表失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg